
package com.kweative.model.query;

import com.kweative.model.Table;
import com.kweative.model.data.Row;
import com.kweative.model.exception.ColumnNotFoundException;
import com.kweative.model.column.Column;
import com.kweative.model.relation.ISimpleRelation;
import com.kweative.model.relation.IMultiRelation;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author henrik
 */
public class Update<T extends Table> extends WhereStatement<Update<T>,T> implements SetterStatement<T>,NonQueryStatement {
    LinkedList<AssignPhrase> assignPhrases = new LinkedList<AssignPhrase>();
    
    public Update(T primTable) {
        super(primTable);
    }
    public Update<T> set(Column<?,T> col,Object value) {
        assignPhrases.add(new AssignPhrase(col, value, this));
        return this;
    }
    public Update<T> set(Column<?,T>[] cols,Object[] values) {
        for(int i = 0; i < cols.length;i++) {
            set(cols[i],values[i]);
        }
        return this;
    }
    public Update<T> set(Map<Column<?,T>,Object> nameValue) {
        for(Column col:nameValue.keySet()) {
            set(col,nameValue.get(col));
        }
        return this;
    }
    public <C extends Table> Update<T> add(IMultiRelation<T, C> relation, Row<T> parent, Row<C> child) {
        relation.add(parent,child);
        return this;
    }

    public <P extends Table> Update<T> set(ISimpleRelation<P,T> relation, Row<P> parent) {
        relation.set(this,parent);
        return this;
    }
    public <C extends Table> Update<T> add(ISimpleRelation<T,C> relation, Row<C> child) {
        relation.add(this,child);
        return this;
    }

    public Update<T> from(Row row) {
        for(Field f: row.getClass().getDeclaredFields()) {
            try {
                Object fVal = f.get(row);
                if (fVal == null) continue;
                Column col = null;
                if (fVal instanceof Row) {
                    fVal = ((Row)fVal).__primary;
                    col = getTable().getParentKey(row);
                } else {
                    col = getTable().getColumn(f.getName());
                }

                set(col, fVal);
            } catch (Exception ex) {
                Logger.getLogger(Insert.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return this;
    }


    @Override
    public String compile() {
        StringBuilder sb = new StringBuilder();
        try {
            String assignPhrase = compileAssignPhrase();
            String wherePhrase = compileWherePhrase();
            String orderPhrase = compileOrderPhrase();

            String limitPhrase = compileLimitPhrase();

            sb.append(String.format("UPDATE %s SET ",QueryUtil.formatTable(getTable())));
            sb.append(assignPhrase);
            if (!wherePhrase.isEmpty())
                sb.append(" WHERE ").append(wherePhrase);
            sb.append(orderPhrase);
            sb.append(limitPhrase);
        } catch (ColumnNotFoundException ex) {
            Logger.getLogger(Delete.class.getName()).log(Level.SEVERE, null, ex);
        }
        return sb.toString();
    }
    protected String compileAssignPhrase() {
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        for(AssignPhrase p: assignPhrases) {
            if (!first) sb.append(",");
			sb.append(QueryUtil.formatColumn(p.getColumn())).append(" = ");
			Object value = p.getColumn().beforeUpdate(p.getValue());
            sb.append(QueryUtil.formatValue(p.getColumn(),value));
            first = false;
        }
        return sb.toString();
    }
}
